home *** CD-ROM | disk | FTP | other *** search
/ Programming Sound Cards / Programming Sound Cards.iso / sound_56 / dspscan.c < prev    next >
Text File  |  1995-01-01  |  31KB  |  1,164 lines

  1. /*=============================================================================*
  2.  * DSPSCAN v3.10 - SoundBlaster Scanning Program
  3.  *    Craig Jackson
  4.  *-----------------------------------------------------------------------------
  5.  * Requires: 8086, DOS 3.0, SoundBlaster
  6.  *-----------------------------------------------------------------------------
  7.  * Revision 1.00    Initial DSPC evaluation (RWR, DMA/IRQ)
  8.  *            2.00    Added DSPC status (0FBh, 0FCh)
  9.  *          3.00    Merged DSPC associativity and read tests, mixer, 0E1h check
  10.  *          3.10    Added BLASTER display, mixer bitscan, wierd TestDSPx DREQs
  11.  *-----------------------------------------------------------------------------
  12.  * ■ Virtualized DMA yields unreliable DMA polling results
  13.  * ■ DSP scanning method 0xE1 returns some invalid information (R:0 W:0 R:0)
  14.  * ■ DSP scanning method 0xFD may return some invalid flags for old cards
  15.  * ■ DSP highspeed commands may not responed to scanning properly
  16.  * ■ DSP commands which lower DREQ are not properly polled (next version)
  17.  * ■ DSP scan mixer register is combination of two samplings.
  18.  * ■ Command line arguments may overflow if larger than 0xFFFF, some unused
  19.  * ■ Unreliable results on IBM PS/2s and most SoundBlaster compatibles
  20.  * ■ Available disk space for log file is not checked
  21.  *-----------------------------------------------------------------------------*/
  22.  
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26.  
  27. typedef unsigned char  BYTE;
  28. typedef unsigned short WORD;
  29.  
  30. typedef int            BOOL;
  31. #define FALSE    0
  32. #define TRUE   (!FALSE)
  33.  
  34. #define isEnabled(x)    ((x) ? txtEnabled : txtDisabled)
  35.  
  36. // Define LOG7BIT to use only ASCII characters in the log file
  37. #ifdef LOG7BIT
  38. #define CHRDEF_DSPSCANE1    '+'
  39. #define CHRDEF_DSPWIERD     'O'
  40. #define CHRDEF_DSPNOTWIERD  '-'
  41. #define CHRDEF_LNA          '-'     // '---'
  42. #define CHRDEF_LNB          '-'     // '---'
  43. #define CHRDEF_LNC          '-'
  44. #else
  45. #define CHRDEF_DSPSCANE1    '+'
  46. #define CHRDEF_DSPWIERD     '■'
  47. #define CHRDEF_DSPNOTWIERD  '-'
  48. #define CHRDEF_LNA          '─'     // '───'
  49. #define CHRDEF_LNB          '-'     // '---'
  50. #define CHRDEF_LNC          ''
  51. #endif  // LOG7BIT
  52.  
  53. #define F_DSPS        0x0001
  54. #define F_DSPA      0x0002
  55. #define F_DSPR      0x0004
  56. #define F_MIXS      0x0008
  57. #define F_MIXB      0x0010
  58. #define F_MIXD      0x0020
  59.  
  60. typedef struct tagDSPC
  61. {
  62.     WORD wFlags;
  63.     BYTE cFB, cFC;
  64.     BYTE cX82;
  65.     int  R0, W0, R1;
  66. }DSPC;
  67.  
  68. #define D_UNKNOWN    0x0000
  69. #define D_KNOWN     0x0001
  70. #define D_IRQ8        0x0002
  71. #define D_IRQ16     0x0004
  72. #define D_IRQMPU    0x0008
  73. #define D_PDMA8HI    0x0010
  74. #define D_PDMA8LO    0x0020
  75. #define D_PDMA16HI    0x0040
  76. #define D_PDMA16LO    0x0080
  77. #define D_WIERD     0x0100
  78.  
  79. typedef struct tagMIXER
  80. {
  81.     BYTE    cFlags;
  82.     BYTE    cResetData;
  83.     BYTE    cOldData;
  84. }MIXER;
  85.  
  86. #define M_STATUS    0x01
  87. #define M_CHANGED    0x02
  88.  
  89. BOOL ResetDSP(void);
  90. BYTE ReadDSP(void);
  91. void WriteDSP(BYTE cData);
  92. void ResetMIX(void);
  93. BYTE ReadMIX(BYTE cIndex);
  94. void WriteMIX(BYTE cIndex, BYTE cData);
  95. BOOL isMixer(void);
  96. BOOL isDSPxFD(void);
  97. BOOL TestDSPxE1(DSPC *pDSPC, int i);    // Method: DSP Version
  98. BOOL TestDSPxFD(DSPC *pDSPC, int i);    // Method: DSP Command Status
  99. BYTE *PtrDSPC(int i, BYTE *pBuf);
  100.  
  101. void Delay(int nTicks);
  102.  
  103. void putslna(void);
  104. void putslnb(void);
  105. void putslnc(void);
  106.  
  107. const char *txtHeader  = "DSP Command Scanner v3.10\n"        \
  108.                          "  Copyright (C) 1994 - Craig Jackson\n\n";
  109. const char *txtOptions = " DSPSCAN <file> [A:<n>] [I:<n>] [D:<n>] [DSP:<min>-<max>] [MIX:<min>-<max>]\n"  \
  110.                          "                [S:<n>] [X:<n>] [MIXER] [NODSPS] [NODSPA] [NODSPR] [NOMIXS]\n"  \
  111.                          "                [NOMIXB] [NOMIXD]\n"                                            \
  112.                          "\n"                                                                             \
  113.                          "  <file>              Output file (required)\n"                                 \
  114.                          "  A:<n>               SoundBlaster base address (default 220)\n"                \
  115.                          "  I:<n>               SoundBlaster IRQ (default 7, ignored on SB16)\n"          \
  116.                          "  D:<n>               SoundBlaster DMA (default 1, ignored on SB16)\n"          \
  117.                          "  DSP:<min>-<max>     Range for DSP command scans (default 00-FF)\n"            \
  118.                          "  MIX:<min>-<max>     Range for mixer index scans (default 00-FF)\n"            \
  119.                          "  S:<n>               Seed value for DSP scan writes (default 00)\n"            \
  120.                          "  X:<n>               Index for DSP command mixer status (default 82)\n"        \
  121.                          "  MIXER               Forces mixer detection\n"                                 \
  122.                          "  NODSPS              Skips DSP command scan\n"                                 \
  123.                          "  NODSPA              Skips DSP command associativity scan\n"                   \
  124.                          "  NODSPR              Skips DSP command read scan\n"                            \
  125.                          "  NOMIXS              Skips mixer index scan\n"                                 \
  126.                          "  NOMIXB              Skips mixer bit scan\n"                                   \
  127.                          "  NOMIXD              Skips mixer defaults scan\n";
  128.  
  129. const char *txtEnabled   = "Enabled";
  130. const char *txtDisabled  = "Disabled";
  131.  
  132. FILE *fp;
  133.  
  134. WORD wBaseAddr = 0x0220;
  135. BYTE cIRQ      = 7,
  136.      cDMA8     = 1,
  137.      cDMA16;
  138. BOOL blMixer   = FALSE;
  139. BYTE cMajorVersion, cMinorVersion;
  140. WORD wFlags    = F_DSPS | F_DSPA | F_DSPR | F_MIXS | F_MIXB | F_MIXD;
  141. BOOL blIOError = FALSE;
  142. WORD nTimeout  = 0xFFFF;
  143. BYTE cSeed       = 0x00;
  144. BYTE cMixerX   = 0x82;
  145.  
  146. BOOL (*fpTestDSP)(DSPC *pDSPC, int i);
  147.  
  148. DSPC    tblDSPC[256];
  149. MIXER   tblMIX[256];
  150.  
  151. BYTE    pBufA[256*2];
  152. BYTE    pBufB[256*2];
  153.  
  154. void main(int argc, char *argv[])
  155. {
  156.     int     minDSPC = 0x00;
  157.     int     maxDSPC = 0xFF;
  158.  
  159.     int     minMIX    = 0x00;
  160.     int     maxMIX    = 0xFF;
  161.  
  162.     int     i, j, k, l, m, n;
  163.     char   *p;
  164.  
  165.     fputs(txtHeader, stderr);
  166.  
  167.     if (argc >= 2)
  168.     {
  169.         fp = fopen(argv[1], "w");
  170.     }
  171.     if (!fp)
  172.     {
  173.         fputs(txtOptions, stderr);
  174.         exit(0);
  175.     }
  176.  
  177.     for (i = 2; i < argc; i++)
  178.     {
  179.         if (!strnicmp(argv[i], "A:", 2))
  180.         {
  181.             wBaseAddr = (BYTE)strtoul(&argv[i][2], NULL, 16);
  182.         }
  183.         else if (!strnicmp(argv[i], "I:", 2))
  184.         {
  185.             if ((cIRQ = (BYTE)atoi(&argv[i][2])) > 15)
  186.             {
  187.                 fputs(" ERROR: SoundBlaster IRQ invalid", stderr);
  188.                 exit(1);
  189.             }
  190.         }
  191.         else if (!strnicmp(argv[i], "D:", 2))
  192.         {
  193.             if (((cDMA8 = (BYTE)atoi(&argv[i][2])) > 3) || (cDMA8 == 2))
  194.             {
  195.                 fputs(" ERROR: SoundBlaster DMA invalid", stderr);
  196.                 exit(1);
  197.             }
  198.         }
  199.         else if (!strnicmp(argv[i], "DSP:", 4))
  200.         {
  201.             minDSPC = strtoul(&argv[i][4], &p, 16);
  202.             maxDSPC = strtoul(p+1, NULL, 16);
  203.             if ((*p != '-') || (minDSPC > maxDSPC))
  204.             {
  205.                 fputs(" ERROR: DSP range invalid", stderr);
  206.                 exit(1);
  207.             }
  208.         }
  209.         else if (!strnicmp(argv[i], "MIX:", 4))
  210.         {
  211.             minMIX = strtoul(&argv[i][4], &p, 16);
  212.             maxMIX = strtoul(p+1, NULL, 16);
  213.             if ((*p != '-') || (minMIX > maxMIX))
  214.             {
  215.                 fputs(" ERROR: Mixer range invalid", stderr);
  216.                 exit(1);
  217.             }
  218.         }
  219.         else if (!strnicmp(argv[i], "S:", 2))
  220.         {
  221.             cSeed = (BYTE)strtoul(&argv[i][2], NULL, 16);
  222.         }
  223.         else if (!strnicmp(argv[i], "X:", 2))
  224.         {
  225.             cMixerX = (BYTE)strtoul(&argv[i][2], NULL, 16);
  226.         }
  227.         else if (!stricmp(argv[i], "MIXER"))
  228.         {
  229.             blMixer = TRUE;
  230.         }
  231.         else if (!stricmp(argv[i], "NODSPS"))
  232.         {
  233.             wFlags &= ~(F_DSPS);
  234.         }
  235.         else if (!stricmp(argv[i], "NODSPA"))
  236.         {
  237.             wFlags &= ~(F_DSPA);
  238.         }
  239.         else if (!stricmp(argv[i], "NODSPR"))
  240.         {
  241.             wFlags &= ~(F_DSPR);
  242.         }
  243.         else if (!stricmp(argv[i], "NOMIXS"))
  244.         {
  245.             wFlags &= ~(F_MIXS);
  246.         }
  247.         else if (!stricmp(argv[i], "NOMIXB"))
  248.         {
  249.             wFlags &= ~(F_MIXB);
  250.         }
  251.         else if (!stricmp(argv[i], "NOMIXD"))
  252.         {
  253.             wFlags &= ~(F_MIXD);
  254.         }
  255.         else
  256.             fprintf(stderr, " WARNING: Unknown option \"%s\"; ignored\n\n", argv[i]);
  257.     }
  258.  
  259.     if (!ResetDSP())
  260.     {
  261.         fputs(" ERROR: Invalid port address", stderr);
  262.         exit(1);
  263.     }
  264.  
  265.     if (!blMixer)
  266.         blMixer = isMixer();
  267.  
  268.     WriteDSP(0xE1);
  269.     cMajorVersion = ReadDSP();
  270.     cMinorVersion = ReadDSP();
  271.  
  272.     WriteDSP(0xE1);
  273.     if ((cMajorVersion != ReadDSP()) || (cMinorVersion != ReadDSP()) || (blIOError))
  274.     {
  275.         fputs(" ERROR: SoundBlaster port address conflicting with another card", stderr);
  276.         exit(1);
  277.     }
  278.  
  279.     putslna();
  280.  
  281. #ifdef LOG7BIT
  282.     fputs("DSPSCAN V3.10 LOGFILE (ASCII)\n", fp);
  283. #else
  284.     fputs("DSPSCAN V3.10 LOGFILE\n", fp);
  285. #endif // LOG7BIT
  286.     putslna();
  287.     fputc('\n', fp);
  288.  
  289.     if (cMajorVersion < 0x04)
  290.     {
  291.         nTimeout  = 0x04FF;     // unsure of exact value
  292.  
  293.         fprintf(fp, "SoundBlaster Port      : %04Xh\n"
  294.                     "            *IRQ       : %2d\n"
  295.                     "            *DMA8      :  %d\n", wBaseAddr, cIRQ, cDMA8);
  296.         if (p = getenv("BLASTER"))
  297.         {
  298.             fprintf(fp, "             BLASTER   : %s\n", p);
  299.         }
  300.         fprintf(fp, "             Version   : %2d.%02d\n\n", cMajorVersion, cMinorVersion);
  301.     }
  302.     else
  303.     {
  304.         nTimeout  = 0x00FF;
  305.  
  306.         if ((k = (int)ReadMIX(0x80)) & 0x08)
  307.             cIRQ = 10;
  308.         else if (k & 0x04)
  309.             cIRQ =    7;
  310.         else if (k & 0x02)
  311.             cIRQ =    5;
  312.         else if (k & 0x01)
  313.             cIRQ =    2;
  314.         else
  315.         {
  316.             fputs(" ERROR: SoundBlaster IRQ indeterminate", stderr);
  317.             exit(3);
  318.         }
  319.  
  320.         if ((k = (int)ReadMIX(0x81)) & 0x08)
  321.             cDMA8 = 3;
  322.         else if (k & 0x02)
  323.             cDMA8 = 1;
  324.         else if (k & 0x01)
  325.             cDMA8 = 0;
  326.         else
  327.         {
  328.             fputs(" ERROR: SoundBlaster DMA8 indeterminate", stderr);
  329.             exit(3);
  330.         }
  331.  
  332.         if (k & 0x80)
  333.             cDMA16 = 7;
  334.         else if (k & 0x40)
  335.             cDMA16 = 6;
  336.         else if (k & 0x20)
  337.             cDMA16 = 5;
  338.         else
  339.         {
  340.             if (wFlags & F_DSPS)
  341.                 fputs(" WARNING: Aliased DMA16, unreliable DSPC scan DMA poll\n", stderr);
  342.             cDMA16 = cDMA8;
  343.         }
  344.  
  345.         fprintf(fp, "SoundBlaster Port      : %04Xh\n"
  346.                     "             IRQ       : %2d\n"
  347.                     "             DMA8      :  %d\n"
  348.                     "             DMA16     :  %d\n", wBaseAddr, cIRQ, cDMA8, cDMA16);
  349.         if (p = getenv("BLASTER"))
  350.         {
  351.             fprintf(fp, "             BLASTER   : %s\n", p);
  352.         }
  353.         fprintf(fp, "             Version   : %2d.%02d\n"
  354.                     "             Copyright :", cMajorVersion, cMinorVersion);
  355.         WriteDSP(0xE3);
  356.         i = (int)' ';
  357.         do
  358.         {
  359. #ifdef LOG7BIT
  360.             fputc((i > 0x7F) ? '?' : i, fp);
  361. #else
  362.             fputc(i, fp);
  363. #endif // LOG7BIT
  364.             i = (int)ReadDSP();
  365.         } while ((blIOError != TRUE) && (i != '\0'));
  366.         fputs("\n\n", fp);
  367.     }
  368.  
  369.     fpTestDSP = (isDSPxFD()) ? TestDSPxFD : TestDSPxE1;
  370.  
  371.     fprintf(fp, "Parameters  %cDSPC Scan             : %-8s (%02X-%02Xh : %02Xh)\n"
  372.                 "             DSPC Associative Scan : %-8s\n"
  373.                 "             DSPC Read Scan        : %-8s\n"
  374.                 "             MIXR Scan             : %-8s (%02X-%02Xh : %02Xh)\n"
  375.                 "             MIXR Bit Scan         : %-8s\n"
  376.                 "             MIXR Defaults Scan    : %-8s\n\n",
  377.                 (fpTestDSP == TestDSPxE1) ? CHRDEF_DSPSCANE1 : ' ',
  378.                 isEnabled(wFlags & F_DSPS), minDSPC, maxDSPC, cSeed,
  379.                 isEnabled(wFlags & F_DSPA),
  380.                 isEnabled(wFlags & F_DSPR),
  381.                 isEnabled((wFlags & F_MIXS) && (blMixer)), minMIX,  maxMIX, cMixerX,
  382.                 isEnabled((wFlags & F_MIXB) && (blMixer)),
  383.                 isEnabled((wFlags & F_MIXD) && (blMixer)));
  384.  
  385.     if (wFlags & (F_DSPS|F_DSPA|F_DSPR))
  386.     {
  387.         fprintf(stderr, "Evaluating DSP   ...      ");
  388.  
  389.         for (i = minDSPC; i <= maxDSPC; i++)
  390.         {
  391.             fprintf(stderr, "\b\b\b\b\b%c 0%02X", (i & 0x0001) ? '■' : '∙', i);
  392.             (*fpTestDSP)(&tblDSPC[i], i);
  393.         }
  394.  
  395.         fputs("\b\b\b\b\b Done\n", stderr);
  396.     }
  397.  
  398.     if (wFlags & F_DSPS)
  399.     {
  400.         putslnb();
  401.         fputs("DSP COMMAND SCAN\n\n", fp);
  402.  
  403.         putslnc();
  404.         for (i = minDSPC; i <= maxDSPC; i++)
  405.         {
  406.             if (tblDSPC[i].wFlags & D_KNOWN)
  407.             {
  408.                /*----------------------------------------------------------------------------*
  409.                  00 - R:00 W:00 R:00 - DACDMA8 ADCDMA8 DACDMA16 ADCDMA16 IRQ8     IRQ16     IRQMPU
  410.                        (FB:00 FC:00)   SPEAKER TIMECNT AUTOINT2 AUTOINT4 DMA8xx  DMA16xx X82:00
  411.                 *----------------------------------------------------------------------------*/
  412.                 fprintf(fp, " %02X %c R%c%02X W:%02X R%c%02X - %7s %7s %8s %8s %7s %7s %6s\n"
  413.                             "        (FB:%02X FC:%02X)  %7s %7s %8s %8s %5s%2s %5s%2s X%02X:%02X\n",
  414.                             i,
  415.                             (tblDSPC[i].wFlags & D_WIERD) ? CHRDEF_DSPWIERD : CHRDEF_DSPNOTWIERD,
  416.                             (tblDSPC[i].R0 == 0xFF) ? '>' : ':', tblDSPC[i].R0,
  417.                             tblDSPC[i].W0,
  418.                             (tblDSPC[i].R1 == 0xFF) ? '>' : ':', tblDSPC[i].R1,
  419.                             (tblDSPC[i].cFB    & 0x01)      ? "DACDMA8"   : "-------",
  420.                             (tblDSPC[i].cFB    & 0x02)      ? "ADCDMA8"   : "-------",
  421.                             (tblDSPC[i].cFB    & 0x04)      ? "DACDMA16"  : "--------",
  422.                             (tblDSPC[i].cFB    & 0x08)      ? "ADCDMA16"  : "--------",
  423.                             (tblDSPC[i].wFlags & D_IRQ8)    ? "IRQ8"      : "-------",
  424.                             (tblDSPC[i].wFlags & D_IRQ16)   ? "IRQ16"     : "-------",
  425.                             (tblDSPC[i].wFlags & D_IRQMPU)  ? "IRQMPU"    : "------",
  426.                             tblDSPC[i].cFB, tblDSPC[i].cFC,
  427.                             (tblDSPC[i].cFB    & 0x10)      ? "SPEAKER"   : "-------",
  428.                             (tblDSPC[i].cFB    & 0x80)      ? "TIMECNT"   : "-------",
  429.                             (tblDSPC[i].cFC    & 0x04)      ? "AUTOINT2"  : "--------",
  430.                             (tblDSPC[i].cFC    & 0x10)      ? "AUTOINT4"  : "--------",
  431.                             (tblDSPC[i].wFlags & (D_PDMA8HI|D_PDMA8LO)) ? "DMA8" : "-----",
  432.                             (tblDSPC[i].wFlags & D_PDMA8HI) ? "HI" : (tblDSPC[i].wFlags & D_PDMA8LO) ? "LO" : "--",
  433.                             (tblDSPC[i].wFlags & (D_PDMA16HI|D_PDMA16LO)) ? "DMA16" : "-----",
  434.                             (tblDSPC[i].wFlags & D_PDMA16HI) ? "HI" : (tblDSPC[i].wFlags & D_PDMA16LO) ? "LO" : "--",
  435.                             cMixerX, tblDSPC[i].cX82);
  436.  
  437.                 putslnc();
  438.             }
  439.         }
  440.     }
  441.  
  442.     if (wFlags & F_DSPA)
  443.     {
  444.         putslnb();
  445.         fputs("DSP ASSOCIATIVE SCAN\n\n", fp);
  446.  
  447.         fputs("Crosslinking DSP ...          ", stderr);
  448.         for (i = minDSPC; i <= maxDSPC; i++)
  449.         {
  450.             fprintf(stderr, "\b\b\b\b\b\b\b\b\b%c 0%02X 000", (i & 0x0001) ? '■' : '·', i);
  451.  
  452.             if ((tblDSPC[i].wFlags & D_KNOWN) && (tblDSPC[i].R0 != 0xFF))
  453.             {
  454.                 for (k = minDSPC; k <= maxDSPC; k++)
  455.                 {
  456.                     fprintf(stderr, "\b\b%02X", k);
  457.  
  458.                     if ((k != i) && (tblDSPC[k].wFlags & D_KNOWN) && (tblDSPC[k].R0 != 0xFF))
  459.                     {
  460.                         ResetDSP();
  461.                         PtrDSPC(i, pBufA);
  462.  
  463.                         WriteDSP((BYTE)k);
  464.                         for (l = 0; l < tblDSPC[k].R0; ReadDSP(), l++)
  465.                             ;
  466.                         for (l = 0; l < tblDSPC[k].W0; WriteDSP(cSeed), l++)
  467.                             ;
  468.                         for (l = 0; l < tblDSPC[k].R1; ReadDSP(), l++)
  469.                             ;
  470.  
  471.                         if (memcmp(pBufA, PtrDSPC(i, pBufB), tblDSPC[i].R0 + tblDSPC[i].R1))
  472.                         {
  473.                             fprintf(fp, " %02X<>%02X - ", i, k);
  474.  
  475.                             for (l = 0, j = 0; l < tblDSPC[i].R0 + tblDSPC[i].R1; l++)
  476.                             {
  477.                                 fprintf(fp, "%02X ", pBufA[l]);
  478.  
  479.                                 if (++j > 21)
  480.                                 {
  481.                                     fprintf(fp, "\n          ");
  482.                                     j = 0;
  483.                                 }
  484.                             }
  485.  
  486.                             fprintf(fp, "\n          ");
  487.  
  488.                             for (l = 0, j = 0; l < tblDSPC[i].R0 + tblDSPC[i].R1; l++)
  489.                             {
  490.                                 fprintf(fp, "%02X ", pBufB[l]);
  491.  
  492.                                 if (++j > 21)
  493.                                 {
  494.                                     fprintf(fp, "\n          ");
  495.                                     j = 0;
  496.                                 }
  497.                             }
  498.  
  499.                             fputc('\n', fp);
  500.                             putslnc();
  501.                         }
  502.                     }
  503.                 }
  504.             }
  505.         }
  506.         fputs("\b\b\b\b\b\b\b\b\b Done    \n", stderr);
  507.     }
  508.  
  509.     if (wFlags & F_DSPR)
  510.     {
  511.         putslnb();
  512.         fputs("DSP READ SCAN\n\n", fp);
  513.  
  514.         fprintf(stderr, "Reading DSP      ...      ");
  515.  
  516.         for (i = minDSPC; i <= maxDSPC; i++)
  517.         {
  518.             fprintf(stderr, "\b\b\b\b\b%c 0%02X", (i & 0x0001) ? '■' : '∙', i);
  519.  
  520.             if (tblDSPC[i].R0 + tblDSPC[i].R1)
  521.             {
  522.                 ResetDSP();
  523.  
  524.                 fprintf(fp, " %02X - ", i);
  525.                 WriteDSP((BYTE)i);
  526.  
  527.                 j = 0;
  528.                 if (tblDSPC[i].R0)
  529.                 {
  530.                     for (k = 0; k < tblDSPC[i].R0; k++)
  531.                     {
  532.                         fprintf(fp, "%02X ", ReadDSP());
  533.                         if (++j > 23)
  534.                         {
  535.                             j = 0;
  536.                             fprintf(fp, "\n      ");
  537.                         }
  538.                     }
  539.                 }
  540.  
  541.                 if ((tblDSPC[i].R0) && (tblDSPC[i].R1))
  542.                 {
  543.                     fprintf(fp, ":: ");
  544.                     if (++j > 23)
  545.                     {
  546.                         j = 0;
  547.                         fprintf(fp, "\n      ");
  548.                     }
  549.                 }
  550.  
  551.                 for (k = 0; k < tblDSPC[i].W0; k++)
  552.                     WriteDSP(cSeed);
  553.  
  554.                 if (tblDSPC[i].R1)
  555.                 {
  556.                     for (k = 0; k < tblDSPC[i].R1; k++)
  557.                     {
  558.                         fprintf(fp, "%02X ", ReadDSP());
  559.                         if (++j > 23)
  560.                         {
  561.                             j = 0;
  562.                             fprintf(fp, "\n      ");
  563.                         }
  564.                     }
  565.                 }
  566.  
  567.                 fputc('\n', fp);
  568.                 putslnc();
  569.             }
  570.         }
  571.  
  572.         fputs("\b\b\b\b\b Done\n", stderr);
  573.     }
  574.  
  575.     if ((wFlags & (F_MIXS|F_MIXB|F_MIXD)) && (blMixer))
  576.     {
  577.         fprintf(stderr, "Evaluating MIXER ...     ");
  578.  
  579.         tblMIX[0x00].cFlags = M_CHANGED;
  580.  
  581.         for (i = (minMIX > 0x00) ? minMIX : 0x01; i <= maxMIX; i++)
  582.             tblMIX[i].cOldData = ReadMIX((BYTE)i);
  583.  
  584.         ResetMIX();
  585.         for (i = (minMIX > 0x00) ? minMIX : 0x01; i <= maxMIX; i++)
  586.         {
  587.             fprintf(stderr, "\b\b\b\b\b%c 0%02X", (i & 0x0001) ? '■' : '∙', i);
  588.  
  589.             tblMIX[i].cResetData = ReadMIX((BYTE)i);
  590.             WriteMIX((BYTE)i, (BYTE)((~tblMIX[i].cResetData) & 0x7F));
  591.  
  592.             tblMIX[i].cFlags = (ReadMIX(0x01) & 0x80) ? 0x00 : M_STATUS;
  593.  
  594.             if (ReadMIX((BYTE)i) != tblMIX[i].cResetData)
  595.                 tblMIX[i].cFlags |= M_CHANGED;
  596.             WriteMIX((BYTE)i, (BYTE)tblMIX[i].cOldData);
  597.  
  598.             ReadMIX((BYTE)i);      // prime status register
  599.         }
  600.  
  601.         for (i = (minMIX > 0x00) ? minMIX : 0x01; i <= maxMIX; i++)
  602.             WriteMIX((BYTE)i, tblMIX[i].cOldData);
  603.  
  604.         fputs("\b\b\b\b\b  Done\n", stderr);
  605.     }
  606.  
  607.     if ((wFlags & F_MIXS) && (blMixer))
  608.     {
  609.         putslnb();
  610.         fputs("MIXER INDEX SCAN\n\n", fp);
  611.  
  612.         for (i = minMIX, j = 0; i <= maxMIX; i++)
  613.         {
  614.             if (tblMIX[i].cFlags & (M_STATUS|M_CHANGED))
  615.             {
  616.                 fprintf(fp, "%c%02X", (tblMIX[i].cFlags & M_STATUS) ? (tblMIX[i].cFlags & M_CHANGED) ? '+' : '*' : ' ', i);
  617.                 if (++j > 25)
  618.                 {
  619.                     j = 0;
  620.                     fputc('\n', fp);
  621.                 }
  622.             }
  623.         }
  624.         if (j != 0)
  625.             fputc('\n', fp);
  626.  
  627.         fputs("\n* STATUS DETECTED   + BOTH DETECTED\n", fp);
  628.     }
  629.  
  630.     if ((wFlags & F_MIXB) && (blMixer))
  631.     {
  632.         fprintf(stderr, "Bitscanning MIXER...      ");
  633.  
  634.         putslnb();
  635.         fputs("MIXER BIT SCAN\n\n", fp);
  636.  
  637.         for (i = (minMIX > 0x00) ? minMIX : 0x01; i <= maxMIX; i++)
  638.         {
  639.             fprintf(stderr, "\b\b\b\b\b%c 0%02X", (i & 0x0001) ? '■' : '∙', i);
  640.  
  641.             if (tblMIX[i].cFlags & (M_STATUS|M_CHANGED))
  642.             {
  643.                 k = ReadMIX((BYTE)i);
  644.  
  645.                 WriteMIX((BYTE)i, 0xFF);
  646.                 l = ReadMIX((BYTE)i);
  647.  
  648.                 WriteMIX((BYTE)i, 0x00);
  649.                 m = ReadMIX((BYTE)i);
  650.  
  651.                 WriteMIX((BYTE)i, (BYTE)k);
  652.  
  653.                 fprintf(fp, " %02X:", i);
  654.                 for (n = 0; n < 8; n++, l <<= 1, m <<= 1)
  655.                 {
  656.                     if (n == 4)
  657.                         fputc('|', fp); // nibble separator
  658.  
  659.                     if ((!(l & 0x80)) && (m & 0x80))
  660.                         fputc('?', fp);
  661.                     else if (!(l & 0x80))
  662.                         fputc('0', fp);
  663.                     else if (m & 0x80)
  664.                         fputc('1', fp);
  665.                     else
  666.                         fputc('*', fp);
  667.                 }
  668.                 fputc(' ', fp);
  669.  
  670.                 if (++j > 4)
  671.                 {
  672.                     j = 0;
  673.                     fputc('\n', fp);
  674.                 }
  675.             }
  676.         }
  677.         if (j != 0)
  678.             fputc('\n', fp);
  679.  
  680.         fputs("\b\b\b\b\b  Done\n", stderr);
  681.     }
  682.  
  683.     if ((wFlags & F_MIXD) && (blMixer))
  684.     {
  685.         putslnb();
  686.         fputs("MIXER DEFAULTS SCAN\n\n", fp);
  687.  
  688.         for (i = minMIX, j = 0; i <= maxMIX; i++)
  689.         {
  690.             fprintf(fp, " %02X%c%02X", i, (tblMIX[i].cFlags & (M_STATUS|M_CHANGED)) ? '=' : '+', tblMIX[i].cResetData);
  691.  
  692.             if (++j > 12)
  693.             {
  694.                 j = 0;
  695.                 fputc('\n', fp);
  696.             }
  697.         }
  698.         if (j != 0)
  699.             fputc('\n', fp);
  700.  
  701.         fputs("\n= DETECTED   + UNDETECTED\n", fp);
  702.     }
  703.  
  704.     putslna();
  705.     exit(0);
  706. }
  707.  
  708. BOOL ResetDSP(void)
  709. {
  710.     __asm
  711.     {
  712.         mov     dx,wBaseAddr
  713.         add     dx,006h
  714.         mov     al,001h
  715.         out     dx,al
  716.         in        al,dx
  717.         in        al,dx
  718.         in        al,dx
  719.         in        al,dx
  720.         xor     al,al
  721.         out     dx,al
  722.     }
  723.  
  724.     return (ReadDSP() == 0xAA) && (blIOError == FALSE);
  725. }
  726.  
  727. BYTE ReadDSP(void)
  728. {
  729.     BYTE retr = 0xFF;
  730.  
  731.     blIOError = TRUE;
  732.     __asm
  733.     {
  734.         mov     dx,wBaseAddr
  735.         add     dx,00Eh
  736.         mov     cx,nTimeout
  737.     L0: in      al,dx
  738.         and     al,080h
  739.         loopz    L0
  740.         jz        L1
  741.         sub     dx,004h
  742.         in        al,dx
  743.         mov     retr,al
  744.         mov     blIOError,FALSE
  745.     L1:
  746.     }
  747.  
  748.     return retr;
  749. }
  750.  
  751. void WriteDSP(BYTE cData)
  752. {
  753.     blIOError = TRUE;
  754.     __asm
  755.     {
  756.         mov     dx,wBaseAddr
  757.         add     dx,00Ch
  758.         mov     cx,nTimeout
  759.     L0: in        al,dx
  760.         and     al,080h
  761.         loopnz    L0
  762.         jnz     L1
  763.         mov     al,cData
  764.         out     dx,al
  765.         mov     blIOError,FALSE
  766.     L1:
  767.     }
  768. }
  769.  
  770. void ResetMIX(void)
  771. {
  772.     __asm
  773.     {
  774.         mov     dx,wBaseAddr
  775.         add     dx,004h
  776.         xor     al,al
  777.         out     dx,al
  778.         inc     dx
  779.         inc     ax
  780.         out     dx,al
  781.         dec     ax
  782.         out     dx,al
  783.     }
  784. }
  785.  
  786. BYTE ReadMIX(BYTE cIndex)
  787. {
  788.     BYTE retr;
  789.  
  790.     blIOError = FALSE;
  791.     __asm
  792.     {
  793.         mov     dx,wBaseAddr
  794.         add     dx,004h
  795.         mov     al,cIndex
  796.         out     dx,al
  797.         inc     dx
  798.         in        al,dx
  799.         mov     retr,al
  800.     }
  801.  
  802.     return retr;
  803. }
  804.  
  805. void WriteMIX(BYTE cIndex, BYTE cData)
  806. {
  807.     blIOError = FALSE;
  808.     __asm
  809.     {
  810.         mov     dx,wBaseAddr
  811.         add     dx,004h
  812.         mov     al,cIndex
  813.         out     dx,al
  814.         inc     dx
  815.         mov     al,cData
  816.         out     dx,al
  817.     }
  818. }
  819.  
  820. BOOL isMixer(void)
  821. {
  822.     BYTE c0, c1;
  823.  
  824.     c0 = ReadMIX(0x04);
  825.     WriteMIX(0x04, (BYTE)~c0);
  826.     c1 = ReadMIX(0x04);
  827.     WriteMIX(0x04, c0);
  828.  
  829.     return (c0 != c1);
  830. }
  831.  
  832. BOOL isDSPxFD(void)
  833. {
  834.     BYTE c;
  835.  
  836.     ResetDSP();
  837.     WriteDSP(0x10);
  838.     WriteDSP(0x80);
  839.  
  840.     WriteDSP(0xFD);
  841.     c = ReadDSP();
  842.  
  843.     ResetDSP();
  844.     if (c != 0x10)
  845.         return FALSE;
  846.  
  847.  
  848.     WriteDSP(0x20);
  849.     ReadDSP();
  850.  
  851.     WriteDSP(0xFD);
  852.     c = ReadDSP();
  853.  
  854.     ResetDSP();
  855.     return (c == 0x20);
  856. }
  857.  
  858. BOOL TestDSPxE1(DSPC *pDSPC, int i)
  859. {
  860.     BYTE cDREQ8;
  861.     BYTE cDDMA8Active, cDDMA8Inactive;
  862.     int  j, k;
  863.  
  864.     pDSPC->wFlags = D_UNKNOWN;
  865.  
  866.     for (j = 0; (j < 0x10) && (!(pDSPC->wFlags & D_KNOWN)); j++)
  867.     {
  868.         ResetDSP();
  869.  
  870.         __asm
  871.         {
  872.             cli
  873.             in        al,008h
  874.             mov     cDREQ8,al
  875.             sti
  876.         }
  877.  
  878.         WriteDSP((BYTE)i);
  879.  
  880.         if (blMixer)
  881.             pDSPC->cX82  = ReadMIX(cMixerX);
  882.  
  883.         for (pDSPC->R0 = -1, blIOError = FALSE;
  884.              (!blIOError) && (pDSPC->R0 != 0xFF); ReadDSP(), pDSPC->R0++)
  885.             ;
  886.  
  887.         for (k = 0, pDSPC->W0 = 0, blIOError = FALSE;
  888.              (k < j) && (!blIOError); k++)
  889.         {
  890.             WriteDSP(cSeed);
  891.             pDSPC->W0++;
  892.         }
  893.  
  894.         if (blMixer)
  895.             pDSPC->cX82 |= ReadMIX(cMixerX);
  896.  
  897.         for (pDSPC->R1 = -1, blIOError = FALSE;
  898.              (!blIOError) && (pDSPC->R1 != 0xFF); ReadDSP(), pDSPC->R1++)
  899.             ;
  900.  
  901.         __asm
  902.         {
  903.             cli
  904.  
  905.             in        al,008h
  906.             mov     ah,al
  907.             xor     al,cDREQ8
  908.             and     al,0B0h
  909.  
  910.             mov     dh,al
  911.  
  912.             mov     cl,cDMA8
  913.             mov     dl,001h
  914.             add     cl,004h
  915.             shl     dl,cl
  916.  
  917.             and     al,ah
  918.             and     al,dl
  919.             mov     cDDMA8Active,al
  920.  
  921.             not     ah
  922.             and     dh,ah
  923.             and     dh,dl
  924.             mov     cDDMA8Inactive,dh
  925.  
  926.             sti
  927.         }
  928.  
  929.         WriteDSP(0xE1);
  930.         if ((ReadDSP() == cMajorVersion) && (ReadDSP() == cMinorVersion) && (!blIOError))
  931.         {
  932.             pDSPC->wFlags |= D_KNOWN |
  933.                              ((cDDMA8Active)    ? D_PDMA8HI  : 0x0000) |
  934.                              ((cDDMA8Inactive)  ? D_PDMA8LO  : 0x0000);
  935.  
  936.             WriteDSP(0xD8);
  937.             pDSPC->cFB |= ReadDSP() & 0x10;
  938.             pDSPC->cFC  = 0x00;
  939.         }
  940.         else if ((pDSPC->R0 + pDSPC->R1) ||
  941.                  (cDDMA8Active | cDDMA8Inactive))
  942.         {
  943.             pDSPC->wFlags |= D_KNOWN | D_WIERD |
  944.                              ((cDDMA8Active)    ? D_PDMA8HI  : 0x0000) |
  945.                              ((cDDMA8Inactive)  ? D_PDMA8LO  : 0x0000);
  946.  
  947.             pDSPC->cFB  = 0x00;
  948.             pDSPC->cFC  = 0x00;
  949.         }
  950.  
  951.         if ((pDSPC->R0 == 0xFF) && (pDSPC->R1 == 0xFF) && (!pDSPC->W0))
  952.             pDSPC->R1 = 0x00;
  953.     }
  954.  
  955.     return (pDSPC->wFlags & D_KNOWN != 0);
  956. }
  957.  
  958. BOOL TestDSPxFD(DSPC *pDSPC, int i)
  959. {
  960.     BYTE cDREQ8, cDREQ16;
  961.     BYTE cDDMA8Active, cDDMA8Inactive;
  962.     BYTE cDDMA16Active, cDDMA16Inactive;
  963.     BYTE cIRQ;
  964.     int  j, k;
  965.  
  966.     pDSPC->wFlags = D_UNKNOWN;
  967.  
  968.     for (j = 0; (j < 0x10) && (!(pDSPC->wFlags & D_KNOWN)); j++)
  969.     {
  970.         ResetDSP();
  971.  
  972.         __asm
  973.         {
  974.             cli
  975.             in        al,008h
  976.             mov     cDREQ8,al
  977.             in        al,0D0h
  978.             mov     cDREQ16,al
  979.             sti
  980.         }
  981.  
  982.         WriteDSP((BYTE)i);
  983.  
  984.         Delay(3);
  985.         cIRQ = ReadMIX(0x82);
  986.  
  987.         pDSPC->cX82 = ReadMIX(cMixerX);
  988.  
  989.         for (pDSPC->R0 = -1, blIOError = FALSE;
  990.              (!blIOError) && (pDSPC->R0 != 0xFF); ReadDSP(), pDSPC->R0++)
  991.             ;
  992.  
  993.         for (k = 0, pDSPC->W0 = 0, blIOError = FALSE;
  994.              (k < j) && (!blIOError); k++)
  995.         {
  996.             WriteDSP(cSeed);
  997.             pDSPC->W0++;
  998.         }
  999.  
  1000.         Delay(3);
  1001.         cIRQ |= ReadMIX(0x82);
  1002.  
  1003.         pDSPC->cX82 |= ReadMIX(cMixerX);
  1004.  
  1005.         for (pDSPC->R1 = -1, blIOError = FALSE;
  1006.              (!blIOError) && (pDSPC->R1 != 0xFF); ReadDSP(), pDSPC->R1++)
  1007.             ;
  1008.  
  1009.         __asm
  1010.         {
  1011.             cli
  1012.  
  1013.             in        al,008h
  1014.             mov     ah,al
  1015.             xor     al,cDREQ8
  1016.             and     al,0B0h
  1017.  
  1018.             mov     dh,al
  1019.  
  1020.             mov     cl,cDMA8
  1021.             mov     dl,001h
  1022.             add     cl,004h
  1023.             shl     dl,cl
  1024.  
  1025.             and     al,ah
  1026.             and     al,dl
  1027.             mov     cDDMA8Active,al
  1028.  
  1029.             not     ah
  1030.             and     dh,ah
  1031.             and     dh,dl
  1032.             mov     cDDMA8Inactive,dh
  1033.  
  1034.  
  1035.             in        al,0D0h
  1036.             mov     ah,al
  1037.             xor     al,cDREQ16
  1038.             and     al,0E0h
  1039.  
  1040.             mov     dh,al
  1041.  
  1042.             mov     dl,001h
  1043.             mov     cl,cDMA16
  1044.             shl     dl,cl
  1045.  
  1046.             and     al,ah
  1047.             and     al,dl
  1048.             mov     cDDMA16Active,al
  1049.  
  1050.             not     ah
  1051.             and     dh,ah
  1052.             and     dh,dl
  1053.             mov     cDDMA16Inactive,dh
  1054.  
  1055.             sti
  1056.         }
  1057.  
  1058.         WriteDSP(0xFD);
  1059.         if ((i == ReadDSP()) && (!blIOError))
  1060.         {
  1061.             // some of these flags may be invalid for some 0xFD DSPs
  1062.             pDSPC->wFlags |= D_KNOWN |
  1063.                              ((cIRQ & 0x0001)   ? D_IRQ8     : 0x0000) |
  1064.                              ((cIRQ & 0x0002)   ? D_IRQ16    : 0x0000) |
  1065.                              ((cIRQ & 0x0004)   ? D_IRQMPU   : 0x0000) |
  1066.                              ((cDDMA8Active)    ? D_PDMA8HI  : 0x0000) |
  1067.                              ((cDDMA8Inactive)  ? D_PDMA8LO  : 0x0000) |
  1068.                              ((cDDMA16Active)   ? D_PDMA16HI : 0x0000) |
  1069.                              ((cDDMA16Inactive) ? D_PDMA16LO : 0x0000);
  1070.  
  1071.             WriteDSP(0xFB);
  1072.             pDSPC->cFB  = ReadDSP();
  1073.  
  1074.             WriteDSP(0xFC);
  1075.             pDSPC->cFC  = ReadDSP();
  1076.         }
  1077.         else if ((pDSPC->R0 + pDSPC->R1) ||
  1078.                  (cDDMA8Active | cDDMA8Inactive | cDDMA16Active | cDDMA16Inactive))
  1079.         {
  1080.             // some of these flags may be invalid for some 0xFD DSPs
  1081.             pDSPC->wFlags |= D_KNOWN | D_WIERD |
  1082.                              ((cIRQ & 0x0001)   ? D_IRQ8     : 0x0000) |
  1083.                              ((cIRQ & 0x0002)   ? D_IRQ16    : 0x0000) |
  1084.                              ((cIRQ & 0x0004)   ? D_IRQMPU   : 0x0000) |
  1085.                              ((cDDMA8Active)    ? D_PDMA8HI  : 0x0000) |
  1086.                              ((cDDMA8Inactive)  ? D_PDMA8LO  : 0x0000) |
  1087.                              ((cDDMA16Active)   ? D_PDMA16HI : 0x0000) |
  1088.                              ((cDDMA16Inactive) ? D_PDMA16LO : 0x0000);
  1089.  
  1090.             pDSPC->cFB  = 0;
  1091.             pDSPC->cFC  = 0;
  1092.         }
  1093.  
  1094.         if ((pDSPC->R0 == 0xFF) && (pDSPC->R1 == 0xFF) && (!pDSPC->W0))
  1095.             pDSPC->R1 = 0x00;
  1096.     }
  1097.  
  1098.     return (pDSPC->wFlags & D_KNOWN != 0);
  1099. }
  1100.  
  1101. BYTE *PtrDSPC(int i, BYTE *pBuf)
  1102. {
  1103.     int   j;
  1104.     BYTE *p = pBuf;
  1105.  
  1106.     WriteDSP((BYTE)i);
  1107.     for (j = 0; j < tblDSPC[i].R0; *p = ReadDSP(), j++, p++)
  1108.         ;
  1109.     for (j = 0; j < tblDSPC[i].W0; WriteDSP(cSeed), j++)
  1110.         ;
  1111.     for (j = 0; j < tblDSPC[i].R1; *p = ReadDSP(), j++, p++)
  1112.         ;
  1113.  
  1114.     return pBuf;
  1115. }
  1116.  
  1117. void Delay(int nTicks)
  1118. {
  1119.     __asm
  1120.     {
  1121.         mov     cx,nTicks
  1122.     L0: in        al,040h
  1123.         jmp     L1
  1124.     L1: in        al,040h
  1125.         mov     ah,al
  1126.  
  1127.     L2: in        al,040h
  1128.         jmp     L3
  1129.     L3: in        al,040h
  1130.         cmp     al,ah
  1131.         je        L2
  1132.  
  1133.         loop    L0
  1134.     }
  1135. }
  1136.  
  1137. void putslna(void)
  1138. {
  1139.     int i;
  1140.  
  1141.     for (i = 0; i < 79; i++)
  1142.         fputc(CHRDEF_LNA, fp);   // '───'
  1143.     fputc('\n', fp);
  1144. }
  1145.  
  1146. void putslnb(void)
  1147. {
  1148.     int i;
  1149.  
  1150.     for (i = 0; i < 79; i++)
  1151.         fputc(CHRDEF_LNB, fp);   // '---'
  1152.     fputc('\n', fp);
  1153. }
  1154.  
  1155. void putslnc(void)
  1156. {
  1157.     int i;
  1158.  
  1159.     fputc(' ', fp);
  1160.     for (i = 1; i < 79; i++)
  1161.         fputc(CHRDEF_LNC, fp);   // ''
  1162.     fputc('\n', fp);
  1163. }
  1164.